package com.izobnehc.rabbit.rabbitgenerator.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlCreateTableParser;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.izobnehc.rabbit.rabbitgenerator.domain.*;
import com.izobnehc.rabbit.rabbitgenerator.dto.GenerateParamDTO;
import com.izobnehc.rabbit.rabbitgenerator.mapper.CodeGenerateMapper;
import com.izobnehc.rabbit.rabbitgenerator.service.CodeGenerateService;
import com.izobnehc.rabbit.rabbitgenerator.vo.CodeGenerateVO;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 11272
 * @date 2023/10/16 21:42
 **/
@Service
public class CodeGenerateServiceImpl implements CodeGenerateService {

    @Autowired
    private CodeGenerateMapper codeGenerateMapper;

    @Autowired
    private Configuration freemarkerConfiguration;

    @Override
    public CodeGenerateVO generate(GenerateParamDTO generateParamDTO) throws IOException, TemplateException {

        // 获取模板元数据信息
        List<GeneTemplateMeta> templateMeta = getTemplateMeta(generateParamDTO.getGeneGlobalConfig().getEntry());

        List<GeneTemplate> geneTemplates = new ArrayList<>();

        // 遍历多表配置信息
        for(CreateTableConfig createTableConfig : generateParamDTO.getCreateTableConfigList()) {
            // 获取建表语句
            String createSql = getCreateSql(createTableConfig.getTableName());
            // 生成表基础信息
            GeneTable geneTable = getGeneTable(createSql);
            // 配置信息
            Map<String, Object> root = getConfigMap(geneTable, generateParamDTO);

            for(GeneTemplateMeta gtm : templateMeta) {
                Template temp = freemarkerConfiguration.getTemplate(gtm.getFtlName());
                StringWriter writer = new StringWriter();
                temp.process(root, writer);

                // 字符串内容
                String content = writer.toString();
                writer.close();

                // 生成文件
                String fileName =  "";
                String fileBasePath = "";
                String filePath = "";
                if(gtm.getType() == 1){
                    fileName = gtm.getPreFex() + geneTable.getTableName() + gtm.getAfterFex();
                    fileBasePath = generateParamDTO.getGeneGlobalConfig().getBasePackage().replaceAll("\\.", "/");
                    filePath = "D://temp/" + fileBasePath + "/" + gtm.getPackagePath().replaceAll("\\.", "/");
                }else if(gtm.getType() == 2) {
                    fileName = gtm.getStaticFileName();
                    fileBasePath = "";
                    filePath = "D://temp/" + fileBasePath + "/" + gtm.getPackagePath().replaceAll("\\.", "/") + geneTable.getTableSubName() + "/";
                }
                File file = new File(filePath);
                boolean mkdirs = file.mkdirs();
                FileWriter fileWriter = new FileWriter(filePath + "/" + fileName + "." + gtm.getFileType());
                temp.process(root, fileWriter);
                fileWriter.close();

                GeneTemplate geneTemplate = new GeneTemplate(content, fileName, gtm.getFileType());
                geneTemplates.add(geneTemplate);
            }
        }

        return new CodeGenerateVO(geneTemplates);
    }

    @Override
    public String getCreateSql(String tableName) {
        // 获取建表语句
        Map<String, String> map = codeGenerateMapper.getCreateSql(tableName);
        return map.get("Create Table");
    }

    @Override
    public GeneTable getGeneTable(String createSql) {
        GeneTable geneTable = new GeneTable();

        MySqlStatementParser parser = new MySqlStatementParser(createSql);
        MySqlCreateTableParser sqlParser = parser.getSQLCreateTableParser();
        SQLCreateTableStatement stat = sqlParser.parseCreateTable();

        // 获取表名
        String tableName = stat.getTableName() == null ? "" : stat.getTableName().replaceAll("`", "");
        if(tableName.length() > 0) {
            tableName = StrUtil.toCamelCase(tableName);
            // 保存小驼峰表名
            geneTable.setTableSubName(tableName);
            tableName = tableName.substring(0, 1).toUpperCase() + tableName.substring(1);
        }
        geneTable.setTableName(tableName);
        // 获取表备注
        geneTable.setTableComment(stat.getComment() == null ? "" : stat.getComment().toString().replaceAll("'", ""));

        List<GeneColumn> geneColumns = new ArrayList<>();
        // 获取列信息
        List<String> columnNames = stat.getColumnNames(true);
        for (String columnName : columnNames) {
            SQLColumnDefinition column = stat.getColumn(columnName);
            GeneColumn geneColumn = new GeneColumn();
            // 列名
            geneColumn.setColumnName(columnName);
            geneColumn.setColumnNameCamel(StrUtil.toCamelCase(columnName));
            // 列注释信息
            geneColumn.setColumnComment(column.getComment() == null ? "" : column.getComment().toString().replaceAll("'", ""));

            // 设置类型
            String columnType = "";
            if(column.getDataType() != null) {
                String type = column.getDataType().toString();
                if(type.contains("bigint")) {
                    columnType = "Long";
                }else if(type.contains("int")) {
                    columnType = "Integer";
                }else if(type.contains("varchar") || type.contains("text") || type.contains("tinytext") || type.contains("mediumtext") || type.contains("longtext")) {
                    columnType = "String";
                }else if(type.contains("time") || type.contains("datetime") || type.contains("date")  ) {
                    columnType = "Date";
                }
            }
            geneColumn.setColumnType(columnType);
            geneColumns.add(geneColumn);
        }
        geneTable.setColumns(geneColumns);
        return geneTable;
    }

    // 获取配置信息
    public Map<String, Object> getConfigMap(GeneTable geneTable, GenerateParamDTO generateParamDTO) {

        GeneModelConfig geneModelConfig = generateParamDTO.getGeneModelConfig();

        GeneGlobalConfig geneGlobalConfig = generateParamDTO.getGeneGlobalConfig();

        GeneImportConfig geneImportConfig = new GeneImportConfig();
        geneImportConfig.setImportDate(geneTable.getColumns().stream().anyMatch(item -> "Date".equals(item.getColumnType())));

        Map<String, Object> root = new HashMap<>();

        root.put("geneTable", geneTable);
        root.put("geneModelConfig", geneModelConfig);
        root.put("geneGlobalConfig", geneGlobalConfig);
        root.put("geneImportConfig", geneImportConfig);

        return root;
    }

    // 获取模板元数据信息
    public List<GeneTemplateMeta> getTemplateMeta(String entry) {
        List<GeneTemplateMeta> gtms = new ArrayList<>();
        GeneTemplateMeta gtmModel = new GeneTemplateMeta("model.ftl", "", "", "java", entry, 1, "");
        GeneTemplateMeta gtmMapperJ = new GeneTemplateMeta("mp_mapper_j.ftl", "", "Mapper", "java", "mapper", 1, "");
        GeneTemplateMeta gtmService = new GeneTemplateMeta("mp_service.ftl", "", "Service", "java", "service", 1, "");
        GeneTemplateMeta gtmServiceImpl = new GeneTemplateMeta("mp_service_impl.ftl", "", "ServiceImpl", "java", "service.impl", 1, "");
        GeneTemplateMeta gtmController = new GeneTemplateMeta("controller_restful.ftl", "", "Controller", "java", "controller", 1, "");
        GeneTemplateMeta gtmMapperXml = new GeneTemplateMeta("mp_mapper_xml.ftl", "", "Mapper", "xml", "xmlMapper", 1, "");
        GeneTemplateMeta gtmVueTable= new GeneTemplateMeta("vue3_table.ftl", "", "", "vue", "vue", 2, "index");
        GeneTemplateMeta gtmVueTableDialog = new GeneTemplateMeta("vue3_dialog.ftl", "", "", "vue", "vue", 2, "Dialog");

        gtms.add(gtmModel);
        gtms.add(gtmMapperJ);
        gtms.add(gtmService);
        gtms.add(gtmServiceImpl);
        gtms.add(gtmController);
        gtms.add(gtmMapperXml);
        gtms.add(gtmVueTable);
        gtms.add(gtmVueTableDialog);

        return gtms;
    }
}
